﻿/*
 * 原作者: blu10ph
 * 
 */
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Windows;

namespace cn.blu10ph.wp.HttpHelper
{
    public class HttpPostHelper
    {
        public HttpPostHelper() { }

        public string UserAgent { get; set; }

        public event PostCompletedHandler PostCompleted;
        public event Action<string> OnGetCookie;

        public void PostAsync(Uri address, Dictionary<string, object> textParams, string cookie)
        {
            string textParamsString = HttpGetHelper.GetQueryStringByParameters(textParams);
            PostAsync(address, textParamsString, cookie);
        }
        public void PostAsync(Uri address, IList<string> parameters, string cookie)
        {
            StringBuilder buffer = new StringBuilder();
            bool notFirst = false;
            foreach (string parameter in parameters)
            {
                if (notFirst)
                {
                    buffer.AppendFormat("&{0}", parameter);
                }
                else
                {
                    buffer.AppendFormat("{0}", parameter);
                    notFirst = true;
                }
            }
            PostAsync(address, buffer.ToString(), cookie);
        }
        public void PostAsync(Uri address, string textParamsString, string cookie)
        {
            HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
            request.Method = "post";
            request.ContentType = "application/x-www-form-urlencoded";
            request.UserAgent = UserAgent;
            if (string.Empty == cookie)
            {
                request.CookieContainer = new CookieContainer();
            }
            else
            {
                request.Headers["Cookie"] = cookie;
            }
            request.BeginGetRequestStream(new AsyncCallback((IAsyncResult asynchronousRequest) =>
            {
                HttpWebRequest _request = asynchronousRequest.AsyncState as HttpWebRequest;
                System.IO.Stream postStream = _request.EndGetRequestStream(asynchronousRequest);
                byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(textParamsString);
                //POST提交服务器的资源
                postStream.Write(byteArray, 0, byteArray.Length);
                postStream.Flush();
                postStream.Close();
                request.BeginGetResponse(new AsyncCallback((IAsyncResult asynchronousResult) =>
                {
                    try
                    {
                        HttpWebRequest __request = asynchronousResult.AsyncState as HttpWebRequest;
                        HttpWebResponse response = (HttpWebResponse)__request.EndGetResponse(asynchronousResult);
                        Stream streamResponse = response.GetResponseStream();
                        StreamReader streamRead = new StreamReader(streamResponse);

                        string responseString = streamRead.ReadToEnd();
                        streamRead.Close();
                        streamResponse.Close();
                        foreach (string key in response.Headers.AllKeys)
                        {
                            if("Set-Cookie".Equals(key)){
                                string value = response.Headers[key];
                                if (!string.Empty.Equals(value))
                                {
                                    OnGetCookie(value);
                                }
                            }
                        }
                        response.Close();
                        Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            PostCompleted(this, new PostCompletedEventArgs(responseString));
                        });
                    }
                    catch (Exception ex)
                    {
                        Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            PostCompleted(this, new PostCompletedEventArgs(ex));
                        });
                    }
                }), request);
            }), request);
        }
        public void UploadAsync(Uri address, Dictionary<string, object> textParams, IDictionary<string, FileItem> fileParams, string cookie)
        {
            // 如果没有文件参数，则走普通POST请求
            if (fileParams == null || fileParams.Count == 0)
            {
                PostAsync(address, textParams, cookie);
                return;
            }

            string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("X"); // 随机分隔线

            HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
            request.Method = "post";
            request.ContentType = "multipart/form-data; charset=utf-8; boundary=" + boundary;
            if (string.Empty == cookie)
            {
                request.CookieContainer = new CookieContainer();
            }
            else
            {
                request.Headers["Cookie"] = cookie;
            }
            request.UserAgent = UserAgent;


            request.BeginGetRequestStream(new AsyncCallback((IAsyncResult asynchronousRequest) =>
            {
                HttpWebRequest _request = asynchronousRequest.AsyncState as HttpWebRequest;
                System.IO.Stream postStream = _request.EndGetRequestStream(asynchronousRequest);
                //POST提交服务器的资源

                byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
                byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");

                // 组装文本请求参数
                string textTemplate = "Content-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
                IEnumerator<KeyValuePair<string, object>> textEnum = textParams.GetEnumerator();
                while (textEnum.MoveNext())
                {
                    string textEntry = string.Format(textTemplate, textEnum.Current.Key, textEnum.Current.Value);
                    byte[] itemBytes = Encoding.UTF8.GetBytes(textEntry);
                    postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
                    postStream.Write(itemBytes, 0, itemBytes.Length);
                }

                // 组装文件请求参数
                string fileTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
                IEnumerator<KeyValuePair<string, FileItem>> fileEnum = fileParams.GetEnumerator();
                while (fileEnum.MoveNext())
                {
                    string key = fileEnum.Current.Key;
                    FileItem fileItem = fileEnum.Current.Value;
                    string fileEntry = string.Format(fileTemplate, key, fileItem.GetFileName(), fileItem.GetMimeType());
                    byte[] itemBytes = Encoding.UTF8.GetBytes(fileEntry);
                    postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
                    postStream.Write(itemBytes, 0, itemBytes.Length);

                    byte[] fileBytes = fileItem.GetContent();
                    postStream.Write(fileBytes, 0, fileBytes.Length);
                }

                postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
                postStream.Flush();
                postStream.Close();


                request.BeginGetResponse(new AsyncCallback((IAsyncResult asynchronousResult) =>
                {
                    try
                    {
                        HttpWebRequest __request = asynchronousResult.AsyncState as HttpWebRequest;
                        HttpWebResponse response = (HttpWebResponse)__request.EndGetResponse(asynchronousResult);
                        Stream streamResponse = response.GetResponseStream();
                        StreamReader streamRead = new StreamReader(streamResponse);

                        string responseString = streamRead.ReadToEnd();
                        streamRead.Close();
                        streamResponse.Close();
                        foreach (string headerKey in response.Headers.AllKeys)
                        {
                            if ("Set-Cookie".Equals(headerKey))
                            {
                                OnGetCookie(response.Headers["Set-Cookie"]);
                            }
                        }
                        response.Close();
                        Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            PostCompleted(this, new PostCompletedEventArgs(responseString));
                        });
                    }
                    catch (Exception ex)
                    {
                        Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            PostCompleted(this, new PostCompletedEventArgs(ex));
                        });
                    }
                }), request);
            }), request);
        }
        public delegate void PostCompletedHandler(object sender, PostCompletedEventArgs e);


        /// <summary>
        /// 获取文件的真实媒体类型。目前只支持JPG, GIF, PNG, BMP四种图片文件。
        /// </summary>
        /// <param name="fileData">文件字节流</param>
        /// <returns>媒体类型</returns>
        public static string GetMimeType(byte[] fileData)
        {
            string suffix = GetFileSuffix(fileData);
            string mimeType;

            switch (suffix)
            {
                case "JPG": mimeType = "image/jpeg"; break;
                case "GIF": mimeType = "image/gif"; break;
                case "PNG": mimeType = "image/png"; break;
                case "BMP": mimeType = "image/bmp"; break;
                default: mimeType = "application/octet-stream"; break;
            }

            return mimeType;
        }

        /// <summary>
        /// 根据文件后缀名获取文件的媒体类型。
        /// </summary>
        /// <param name="fileName">带后缀的文件名或文件全名</param>
        /// <returns>媒体类型</returns>
        public static string GetMimeType(string fileName)
        {
            string mimeType;
            fileName = fileName.ToLower();

            if (fileName.EndsWith(".bmp", StringComparison.CurrentCulture))
            {
                mimeType = "image/bmp";
            }
            else if (fileName.EndsWith(".gif", StringComparison.CurrentCulture))
            {
                mimeType = "image/gif";
            }
            else if (fileName.EndsWith(".jpg", StringComparison.CurrentCulture) || fileName.EndsWith(".jpeg", StringComparison.CurrentCulture))
            {
                mimeType = "image/jpeg";
            }
            else if (fileName.EndsWith(".png", StringComparison.CurrentCulture))
            {
                mimeType = "image/png";
            }
            else
            {
                mimeType = "application/octet-stream";
            }

            return mimeType;
        }

        /// <summary>
        /// 获取文件的真实后缀名。目前只支持JPG, GIF, PNG, BMP四种图片文件。
        /// </summary>
        /// <param name="fileData">文件字节流</param>
        /// <returns>JPG, GIF, PNG or null</returns>
        public static string GetFileSuffix(byte[] fileData)
        {
            if (fileData == null || fileData.Length < 10)
            {
                return null;
            }

            if (fileData[0] == 'G' && fileData[1] == 'I' && fileData[2] == 'F')
            {
                return "GIF";
            }
            else if (fileData[1] == 'P' && fileData[2] == 'N' && fileData[3] == 'G')
            {
                return "PNG";
            }
            else if (fileData[6] == 'J' && fileData[7] == 'F' && fileData[8] == 'I' && fileData[9] == 'F')
            {
                return "JPG";
            }
            else if (fileData[0] == 'B' && fileData[1] == 'M')
            {
                return "BMP";
            }
            else
            {
                return null;
            }
        }
    }
}
